package com.privasphere.wikidoclet.dataTransport;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sourceforge.jwbf.core.actions.util.ActionException;
import net.sourceforge.jwbf.core.actions.util.ProcessException;
import net.sourceforge.jwbf.core.contentRep.Article;
import net.sourceforge.jwbf.core.contentRep.SimpleArticle;
import net.sourceforge.jwbf.mediawiki.bots.MediaWikiBot;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.privasphere.wikidoclet.util.WikiDocletCfg;

/**
 * That is the class that takes care of the data transport from the xml file to
 * the chosen MediaWiki
 * 
 * @author Christian Dubs
 * 
 */
public class WikiTransporterJWBF implements Transportable{

	private static final Logger LOGGER = LoggerFactory.getLogger(WikiTransporterJWBF.class.getName());
	private static final WikiDocletCfg CFG = WikiDocletCfg.getInstance();
	
	private MediaWikiBot myMediaWiki;
	private Map<String, WikiDocMetaData> wikiDocPagesMetaData; 
	private List<WikiDocPageData> newWikiDocPagesList;
	private ThreadCoordinator thCoordinator;

	/**
	 * Default constructor only used for setting a default connection.
	 */
	public WikiTransporterJWBF(){
		LOGGER.info("WikiTransporter application started.");
	}
	
	
	/**
	 * That is the constructor that sets the necessary instance variables (newWikiDocPagesList, wikiDocPagesMetaData).
	 * @param xmlFileLocString
	 *            - A String that represents the full path to the xml file. Can
	 *            be filled over command line.
	 * @param xmlFileSchemaLocString
	 *            - A String that represent the full path to the xml scheme
	 *            file. Can be filled over the command line.
	 * 
	 * @throws ActionException
	 * @throws MalformedURLException
	 * @throws ProcessException
	 */
	public WikiTransporterJWBF(List<WikiDocPageData> newWikiDocPagesList, HashMap<String, WikiDocMetaData> wikiDocPagesMetaData, ThreadCoordinator thCoord){
		this();
		this.newWikiDocPagesList = newWikiDocPagesList;
		this.wikiDocPagesMetaData = wikiDocPagesMetaData;
		this.thCoordinator = thCoord;
	}
	
	/**
	 * 
	 */
	@Override
	public boolean initCommunicationChannel(){
		try {
			myMediaWiki = new MediaWikiBot(CFG.getConfigValue(WikiDocletCfg.CFG_PAR_URL));
			myMediaWiki.login(CFG.getConfigValue(WikiDocletCfg.CFG_PAR_UNAME), CFG.getConfigValue(WikiDocletCfg.CFG_PAR_PASSWD));
		} catch (MalformedURLException e) {
			LOGGER.error(e.getMessage());
			System.exit(-1);
		} catch (ActionException e) {
			LOGGER.error(e.getMessage());
			System.exit(-1);
		}
		
		return myMediaWiki.isLoggedIn();
	}
	
	/**
	 * 
	 * @param indexPageIdentifier
	 * @return
	 */
	public HashMap<String, WikiDocMetaData> getWikiPagesMetaData(String indexPageIdentifier){
		try {
			 return WikiDocPageMetaDataParser.parseWikiDocMetaData(myMediaWiki.readContent(indexPageIdentifier).getText());
		} catch (ActionException e) {
			LOGGER.error(e.getMessage());
			System.exit(-1);
		} catch (ProcessException e) {
			LOGGER.error(e.getMessage());
			System.exit(-1);
		}
		//should never come here!
		return null;
	}

	/**
	 * 
	 */
	@Override
	public void transportPages(){
		
		for(WikiDocPageData wikiDocPageData : newWikiDocPagesList) {

			if (wikiDocPagesMetaData == null) {
				// There are no meta data existing --> import all wiki pages!
				writeArticle(wikiDocPageData);
			} else if (wikiDocPagesMetaData.containsKey(wikiDocPageData.getTitleValue())) {

				if (!(wikiDocPagesMetaData.get(wikiDocPageData.getTitleValue()).getHash().equals(wikiDocPageData.getHashValue()))) {
					writeArticle(wikiDocPageData);
				}
				// If equal or not equal hash values; set anyway the delete
				// flag. --> Sign for do not touch the articles
				wikiDocPagesMetaData.remove(wikiDocPageData.getTitleValue());
			} else {
				//There are already existing pages on wiki, but there are new pages in the transport xml file.
				//Know make an import of this new pages.
				writeArticle(wikiDocPageData);
			}
		}

		if (wikiDocPagesMetaData != null) {
		//	removeOldWikiDocPages();
			thCoordinator.setOldWikiPagesInfo(wikiDocPagesMetaData);
		}
		thCoordinator.threadFinished();
		LOGGER.info("WikiTransporter application ended successfully.");
	}

	
	private void writeArticle(WikiDocPageData wikiDocPageData){
		SimpleArticle mySimpleWikiDocArticle;
		Article myWikiDocArticle;
		mySimpleWikiDocArticle = new SimpleArticle();
		myWikiDocArticle = new Article(myMediaWiki, mySimpleWikiDocArticle);

		myWikiDocArticle.setTitle(wikiDocPageData.getTitleValue());
		mySimpleWikiDocArticle.addText(wikiDocPageData.getContentValue());
		LOGGER.debug("Try to write {}", myWikiDocArticle.getTitle());
		try {
			myWikiDocArticle.save("WikiDoclet: Page has been updated");
		} catch (ActionException e) {
			File f = new File("error.log");
			// Create Folders if Required
			if (f.getParent() != null) {
				new File(f.getParent()).mkdirs();
			}
			
			try {
				FileWriter f0 = new FileWriter(f);
				
				f0.write("blub" + e.getMessage());
				f0.flush();
				f0.close();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
				
			LOGGER.error("ActionException ",  e);
			System.exit(-1);
		} catch (ProcessException e) {
			File f = new File("error.log");
			// Create Folders if Required
			if (f.getParent() != null) {
				new File(f.getParent()).mkdirs();
			}
			
			try {
				FileWriter f0 = new FileWriter(f);
				
				f0.write("blub" + e.getMessage());
				f0.flush();
				f0.close();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			LOGGER.error("ProcessException ", e);
			System.exit(-1);
		}
		LOGGER.debug("Article has been written: {}", myWikiDocArticle.getTitle());
	}
	
	public void removeOldWikiDocPages(Map<String, WikiDocMetaData> oldWikiPagesMetaDatas) {
		Article articleToDel;
		for (Map.Entry<String, WikiDocMetaData> page : oldWikiPagesMetaDatas.entrySet()) {
			try {
				//TODO: check wether really to delete the page or save it only empty.
				articleToDel = myMediaWiki.readContent(page.getValue().getPageTitle());
				articleToDel.delete();
				LOGGER.debug("Deleting {}", articleToDel.getTitle());
				//articleToDel.save("WikiDoclet: Page is deprecated");
			} catch (RuntimeException e) {
				LOGGER.warn(e.getMessage());
			}catch (ActionException e) {
				LOGGER.error(e.getMessage());
				System.exit(-1);
			} catch (ProcessException e) {
				LOGGER.error(e.getMessage());
				System.exit(-1);
			}
		}
	}
}